package www.wen.com.common.lib.util

import android.content.Context
import android.util.DisplayMetrics
import android.util.TypedValue.*
import android.view.View
import android.view.WindowManager
import android.widget.LinearLayout.HORIZONTAL
import android.widget.LinearLayout.VERTICAL
import androidx.annotation.FloatRange
import www.wen.com.common.lib.app.BaseApplication.Companion.CONTEXT


/**
 * @author WEN
 * @Description:
 * @date 2020/11/23 21:58
 */

/**
 * dp,sp 和 px 转换的辅助类
 */
class DisplayUtil private constructor() {

    companion object {
        /**
         * 将px值转换为dip或dp值，保证尺寸大小不变
         * DisplayMetrics类中属性density
         */
        @JvmStatic
        fun px2dip(pxValue: Float, context: Context = CONTEXT): Float {
            val scale: Float = context.resources.displayMetrics.density
            return pxValue / scale + 0.5f
        }

        /**
         * 将dip或dp值转换为px值，保证尺寸大小不变
         * DisplayMetrics类中属性density
         */
        @JvmStatic
        fun dip2px(dipValue: Float, context: Context = CONTEXT): Float {
            val scale: Float = context.resources.displayMetrics.density
            return dipValue * scale + 0.5f
        }

        /**
         * 将px值转换为sp值，保证文字大小不变
         * DisplayMetrics类中属性scaledDensity
         */
        @JvmStatic
        fun px2sp(pxValue: Float, context: Context = CONTEXT): Float {
            val fontScale: Float = context.resources.displayMetrics.scaledDensity
            return pxValue / fontScale + 0.5f
        }

        /**
         * 将sp值转换为px值，保证文字大小不变
         * DisplayMetrics类中属性scaledDensity
         */
        @JvmStatic
        fun sp2px(context: Context = CONTEXT, spValue: Float): Int {
            val fontScale: Float = context.resources.displayMetrics.scaledDensity
            return (spValue * fontScale + 0.5f).toInt()
        }

        /**
         * 将px值转换为mm值
         * DisplayMetrics类中属性scaledDensity
         */
        @JvmStatic
        fun px2mm(value: Float, context: Context = CONTEXT): Float {
            return value*25.4f/ context.resources.displayMetrics.xdpi
        }

        /**
         * 将px值转换为mm值
         * DisplayMetrics类中属性scaledDensity
         */
        @JvmStatic
        fun mm2px(value: Float, context: Context = CONTEXT): Float {
            return value * context.resources.displayMetrics.xdpi * (1.0f / 25.4f)
        }

        /**
         * 将pt值转换为px值
         * DisplayMetrics类中属性scaledDensity
         */
        @JvmStatic
        fun pt2px(value: Float, context: Context = CONTEXT): Float {
            return applyDimension(COMPLEX_UNIT_PT,value,context.resources.displayMetrics)
        }

        /**
         * 将px值转换为pt值
         * DisplayMetrics类中属性scaledDensity
         */
        @JvmStatic
        fun px2pt(value: Float, context: Context = CONTEXT): Float {
            return (value*72)/context.resources.displayMetrics.xdpi
        }

        /**
         * 将sp值转换为px值
         * DisplayMetrics类中属性scaledDensity
         */
        @JvmStatic
        fun sp2px(value: Float, context: Context = CONTEXT): Float {
            return applyDimension(COMPLEX_UNIT_SP,value,context.resources.displayMetrics)
        }

        /**
         * 将pt值转换为px值
         * DisplayMetrics类中属性scaledDensity
         */
        @JvmStatic
        fun in2px(value: Float, context: Context = CONTEXT): Float {
            return applyDimension(COMPLEX_UNIT_IN,value,context.resources.displayMetrics)
        }

        @JvmStatic
        fun applyDimension(
            value: Float,
            unitFrom: Int = COMPLEX_UNIT_PX,
            unitOut: Int = COMPLEX_UNIT_PX
        ): Float {
            when (unitFrom) {
                COMPLEX_UNIT_PX ->
                    when (unitOut) {
                        COMPLEX_UNIT_PX -> return value
                        COMPLEX_UNIT_DIP -> return px2dip(value)
                        COMPLEX_UNIT_SP -> return px2sp(value)
                        COMPLEX_UNIT_MM -> return px2mm(value)
                        COMPLEX_UNIT_PT -> return px2pt(value)
                    }
                COMPLEX_UNIT_DIP ->
                    when (unitOut) {
                        COMPLEX_UNIT_PX -> return value
                        COMPLEX_UNIT_DIP -> return dip2px(value)
                    }

                COMPLEX_UNIT_PT ->
                    when (unitOut) {
                        COMPLEX_UNIT_PX -> return pt2px(value)
                    }
            }
            return 0f
        }


        /**
         * 返回屏幕宽度
         * @param unitFrom 输入参数的单位值
         * @param unitOut 输出参数的单位值
         */
        @JvmStatic
        fun getScreenWidth(
            unitFrom: Int = COMPLEX_UNIT_PX,
            unitOut: Int = COMPLEX_UNIT_PX,
            context: Context = CONTEXT
        ): Float {
            val m = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
            val outMetrics = DisplayMetrics()
            m.defaultDisplay.getMetrics(outMetrics)
            outMetrics.widthPixels.toFloat()
            return applyDimension(outMetrics.widthPixels.toFloat(), unitFrom, unitOut)
        }

        /**
         * 得到屏幕的高度
         * @param unitFrom 输入参数的单位值
         * @param unitOut 输出参数的单位值
         */
        @JvmStatic
        fun getScreenHeight(
            unitFrom: Int = COMPLEX_UNIT_PX,
            unitOut: Int = COMPLEX_UNIT_PX,
            context: Context = CONTEXT
        ): Float {
            val m = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
            val outMetrics = DisplayMetrics()
            m.defaultDisplay.getMetrics(outMetrics)
            return applyDimension(outMetrics.heightPixels.toFloat(), unitFrom, unitOut)
        }

        /**
         * 得到屏幕的宽度一定比例的长度
         */
        fun getRatioWidthFromScreen(
            @FloatRange(from = 0.0, to = 1.0) ratio: Float,
            unitFrom: Int = COMPLEX_UNIT_PX,
            unitOut: Int = COMPLEX_UNIT_PX,
            context: Context = CONTEXT
        ): Float {
            return getScreenWidth(unitFrom, unitOut, context) * ratio
        }

        /**
         * 得到以屏幕的高度为基础一定比例的长度
         */
        fun getRatioHeightFromScreen(
            @FloatRange(from = 0.0, to = 1.0) ratio: Float,
            unitFrom: Int = COMPLEX_UNIT_PX,
            unitOut: Int = COMPLEX_UNIT_PX,
            context: Context = CONTEXT
        ): Float {
            return getScreenHeight(unitFrom, unitOut, context) * ratio
        }

        /**
         * 以view自身的宽或高为基础返回一定宽高比的view
         * @param ratio 宽高比
         */
        fun <T : View> setViewRatio(
            view: T,
            ratio: Float,
            orientation: Int = HORIZONTAL
        ): T {
            view.post {
                when (orientation) {
                    HORIZONTAL -> view.layoutParams.height = (view.width / ratio).toInt()
                    VERTICAL -> view.layoutParams.width = (view.height * ratio).toInt()
                }
            }
            return view
        }

        /**
         * 返回以占屏幕高度或者宽度一定比例并且有一定的宽高比的view
         * @param ratio 宽高比
         * @param ratioScreen view的宽度占屏幕宽度 或者 view的高度占屏幕高度或者的比例
         */
        fun <T : View> setViewRatioForScreen(
            view: T,
            orientation: Int = HORIZONTAL,
            @FloatRange(from = 0.0, to = 1.0) ratio: Float = 1f,
            @FloatRange(from = 0.0, to = 1.0) ratioScreen: Float
        ): T {
            when (orientation) {
                HORIZONTAL -> {
                    view.layoutParams.width = (getScreenWidth() * ratioScreen).toInt()
                    view.layoutParams.height = (view.width / ratio).toInt()
                }
                VERTICAL -> {
                    view.layoutParams.height = (getScreenHeight() * ratioScreen).toInt()
                    view.layoutParams.width = (view.height * ratio).toInt()
                }
            }
            return view
        }

    }

    init {
        /* cannot be instantiated */
        throw UnsupportedOperationException("cannot be instantiated")
    }

}